package licode.unisop.single.user.infrastructure.repository.dao;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import licode.unisop.provider.info.*;
import licode.unisop.provider.vo.SiPageResult;
import licode.unisop.provider.vo.SiRealmPlatform;
import licode.unisop.provider.vo.SiUserGroup;
import licode.unisop.single.user.application.entity.RealmPlatGroupEntity;
import licode.unisop.single.user.application.gateway.RealmAssetDao;
import licode.unisop.single.user.application.gateway.RealmPlatGroupDao;
import licode.unisop.single.user.infrastructure.assembler.UniUserSingleAssembler;
import licode.unisop.single.user.infrastructure.repository.mapper.RealmPlatGroupMapper;
import licode.unisop.single.user.infrastructure.repository.po.RealmPlatGroupPO;
import licode.unisop.single.user.infrastructure.utils.PageUtil;
import licode.unisop.types.util.IdGenUtil;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * uni-user-single
 *
 * @author licode
 * @date 2016-04-11 10:58:29
 */
@Component
public class RealmPlatGroupDaoImpl
        extends ServiceImpl<RealmPlatGroupMapper, RealmPlatGroupPO>
        implements RealmPlatGroupDao {
    @Resource
    private RealmAssetDao realmAssetDao;

    @Resource
    private UniUserSingleAssembler uniUserSingleAssembler;

    @Override
    public void add(RealmPlatGroupEntity item) {
        super.save(uniUserSingleAssembler.fromRealmPlatGroupEntity(item));
    }

    @Override
    public void update(RealmPlatGroupEntity item) {
        super.updateById(uniUserSingleAssembler.fromRealmPlatGroupEntity(item));
    }

    @Override
    public void removeWithId(Serializable id) {
        super.removeById(id);
    }

    @Override
    public RealmPlatGroupEntity getWithId(Serializable id) {
        return uniUserSingleAssembler.fromRealmPlatGroup(super.getById(id));
    }

    @Override
    public void clearGroupsOfPlatform(String platformId) {
        super.lambdaUpdate()
                .eq(RealmPlatGroupPO::getPlatformId, platformId)
                .remove();
    }

    @Override
    public void saveGroupsOfPlatform(SiUserGroupsAssignToPlatIn req) {
        List<RealmPlatGroupPO> addItems = new ArrayList<>();
        req.getGroups().forEach(item -> {
            RealmPlatGroupPO groupItem = new RealmPlatGroupPO();
            groupItem.setId(IdGenUtil.buildUserGroupAssignId());
            groupItem.setRealmId(req.getRealmId());
            groupItem.setPlatformId(req.getPlatformId());
            groupItem.setGroupId(item);
            groupItem.setUpdateTime(LocalDateTime.now());
            groupItem.setCreateTime(groupItem.getUpdateTime());
            groupItem.setState(1);
            addItems.add(groupItem);
        });

        super.saveBatch(addItems);
    }

    @Override
    public void assignGroupToPlatform(SiUserGroupsAssignToPlatIn req) {
        List<RealmPlatGroupPO> addItems = new ArrayList<>();
        req.getGroups().forEach(item -> {
            RealmPlatGroupPO groupItem = new RealmPlatGroupPO();

            groupItem.setId(IdGenUtil.buildUserGroupAssignId());
            groupItem.setRealmId(req.getRealmId());
            groupItem.setPlatformId(req.getPlatformId());
            groupItem.setGroupId(item);
            groupItem.setUpdateTime(LocalDateTime.now());
            groupItem.setCreateTime(groupItem.getUpdateTime());
            groupItem.setState(1);
            addItems.add(groupItem);
        });

        super.saveBatch(addItems);
    }

    @Override
    public long getGroupCountToPlatform(UserGroupRemoveFromPlatIn req) {
        return super.lambdaQuery()
                .eq(RealmPlatGroupPO::getRealmId, req.getRealmId())
                .eq(RealmPlatGroupPO::getPlatformId, req.getPlatformId())
                .count();
    }

    @Override
    public void removeGroupFromPlatform(UserGroupRemoveFromPlatIn req) {
        super.lambdaUpdate()
                .eq(RealmPlatGroupPO::getRealmId, req.getRealmId())
                .eq(RealmPlatGroupPO::getPlatformId, req.getPlatformId())
                .in(RealmPlatGroupPO::getGroupId, req.getGroups())
                .remove();
    }

    @Override
    public void removePlatsFromGroup(SiPlatsAssignToUserGroupIn req) {
        super.lambdaUpdate()
                .eq(RealmPlatGroupPO::getRealmId, req.getRealmId())
                .eq(RealmPlatGroupPO::getGroupId, req.getGroupId())
                .in(RealmPlatGroupPO::getPlatformId, req.getPlatIds())
                .remove();
    }

    @Override
    public void assignPlatsToUserGroup(SiPlatsAssignToUserGroupIn req) {
        List<RealmPlatGroupPO> addItems = new ArrayList<>();
        req.getPlatIds().forEach(item -> {
            RealmPlatGroupPO groupItem = new RealmPlatGroupPO();

            groupItem.setId(IdGenUtil.buildUserGroupAssignId());
            groupItem.setRealmId(req.getRealmId());
            groupItem.setPlatformId(item);
            groupItem.setGroupId(req.getGroupId());
            groupItem.setUpdateTime(LocalDateTime.now());
            groupItem.setCreateTime(groupItem.getUpdateTime());
            groupItem.setState(1);
            addItems.add(groupItem);
        });

        super.saveBatch(addItems);
    }

    @Override
    public RealmPlatGroupPO findFirstGroupOfPlatform(String platformId) {
        List<RealmPlatGroupPO> result = super.lambdaQuery()
                .eq(RealmPlatGroupPO::getPlatformId, platformId)
                .last("limit 1")
                .list();
        return null != result && !result.isEmpty() ? result.get(0) : null;
    }

    @Override
    public List<SiUserGroup> findAssignGroup(UserGroupQueryIn req) {
        List<RealmPlatGroupPO> groups = super.lambdaQuery()
                .eq(RealmPlatGroupPO::getRealmId, req.getRealmId())
                .eq(RealmPlatGroupPO::getPlatformId, req.getPlatformId())
                .list();
        if (null == groups || groups.isEmpty()) {
            return null;
        } else {
            return realmAssetDao.findUserGroupList(req.getRealmId(), groups.stream()
                    .map(RealmPlatGroupPO::getGroupId).collect(Collectors.toList()));
        }
    }

    @Override
    public SiPageResult<SiRealmPlatform> findRealPlatform(SiRealmAssignPlatPageIn req) {
        Page<RealmPlatGroupPO> page = new Page<>(req.getCurrent(), req.getPageSize());
        page = super.lambdaQuery()
                .eq(RealmPlatGroupPO::getRealmId, req.getRealmId())
                .in(null != req.getGroups() && !req.getGroups().isEmpty(),
                        RealmPlatGroupPO::getGroupId, req.getGroups())
                .eq(null != req.getState(), RealmPlatGroupPO::getState, req.getState())
                .orderByDesc(RealmPlatGroupPO::getCreateTime)
                .page(page);
        return PageUtil.convertPage(page, this::convertToRealmPlatform);
    }

    @Override
    public List<SiRealmPlatform> findRealPlatformOther(SiRealmPlatformOtherIn req) {
        List<RealmPlatGroupPO> result = super.lambdaQuery()
                .ne(RealmPlatGroupPO::getRealmId, req.getRealmId())
                .list();
        return null == result ? new ArrayList<>() : convertToRealmPlatform(result);
    }

    public List<SiRealmPlatform> convertToRealmPlatform(List<RealmPlatGroupPO> rpList) {
        List<SiRealmPlatform> targetRl = new ArrayList<>();

        rpList.forEach(item -> targetRl.add(SiRealmPlatform.builder()
                .id(item.getId())
                .realmId(item.getRealmId())
                .groupId(item.getGroupId())
                .platformId(item.getPlatformId())
                .state(item.getState())
                .props(item.getProps())
                .updateTime(item.getUpdateTime())
                .createTime(item.getCreateTime())
                .build()));

        return targetRl;
    }
}
